-- ActivityM
-- Created by chengb May/7/2016
-- 活动模块

module("ActivityM", package.seeall);

local PURE_FILE = "ActivityM";

-- 配置表
local activityTable = {};
local activityExchangeTable = {};
local exchangeTableByActivity = {};

-- 正在进行中的活动
local currentActivities = {};

-- 曾经是否开放过活动
local activityOpenList = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 载入活动配置表
    activityTable = {};
    local activity_CSV = get_activity_CSV();
    for i = 1, #activity_CSV do
        local id = activity_CSV[i].id;
        activityTable[id] = activity_CSV[i];
    end
    activity_CSV = nil;

    -- 载入活动兑换配置表
    activityExchangeTable = {};
    local activity_exchange_CSV = get_activity_exchange_CSV();
    for i = 1, #activity_exchange_CSV do
        local row = activity_exchange_CSV[i];
        local id = row.id;
        activityExchangeTable[id] = row;

        -- 根据活动存放兑换配置
        local activityId = row.activity;
        if exchangeTableByActivity[activityId] == nil then
            exchangeTableByActivity[activityId] = {};
        end
        table.insert(exchangeTableByActivity[activityId], row);
    end

    activity_exchange_CSV = nil;

    -- 根据前置ID再整理一遍
    for _, id in pairs(table.keys(activityExchangeTable)) do
        local info = activityExchangeTable[id];
        if tonumber(info.pre_id) > 0 then
            -- 前置项目加上后置ID
            activityExchangeTable[info.pre_id]["after_id"] = id;
        end
    end

    -- 清空列表
    currentActivities = {};
    activityOpenList = {};
end

-- 模块初始化
function init()
    -- 载入活动配置表
    loadCsv();
end

-- 检索活动配置
function query(id, path)
    if not activityTable[id] then
        return nil;
    end

    if path == nil or path == "" then
        return activityTable[id];
    end

    return activityTable[id][path];
end

-- 检索活动兑换配置
function queryExchange(id, path)
    if not activityExchangeTable[id] then
        return nil;
    end

    if path == nil or path == "" then
        return activityExchangeTable[id];
    end

    return activityExchangeTable[id][path];
end

-- 活动功能是否开启
function isActivityFuncOpen()
    if #table.keys(currentActivities) > 0 then
        return true;
    end
    return false;
end

-- 某个活动是否在进行中
function isDuringActivity(id)
    return getRemainTime(id) > 0;
end

-------------------
-- 获取活动剩余开放时间
-- @param id 活动id
-- @return 剩余的秒数
function getRemainTime(id)
    local info = currentActivities[id];
    if not info then
        -- 活动不在进行中
        return 0;
    end

    local serverTime = TimeM.getServerTime();
    if serverTime < info.end_time then
        return info.end_time - serverTime;
    end

    -- 活动已经结束了
    return 0;
end

-------------------
-- 获取活动剩余运行时间
-- @param id 活动id
-- @return 剩余的秒数
function getRemainRunningTime(id)
    local info = currentActivities[id];
    if not info then
        -- 活动不在进行中
        return 0;
    end

    local serverTime = TimeM.getServerTime();
    if serverTime < info.close_time then
        return info.close_time - serverTime;
    end

    -- 活动已经结束了
    return 0;
end

-- 更新当前正在进行中的活动
function updateCurrentActivities(activities)
    assert(type(activities) == "table");
    currentActivities = activities;
end

-- 通知活动信息变化
function notifyActivityChange(id, activityInfo)
    currentActivities[id] = activityInfo;
    EventMgr.fire(event.ACTIVITY_CHANGE, { ["id"] = id, ["status"] = getActivityStatus(activityInfo), });
end

-- 通知某个活动关闭了
function notifyActivityClose(id)
    currentActivities[id] = nil;

    -- 删除活动浮岛
    local pos;
    local skyExplore = ME.user.dbase:query("sky_explore", {});
    for index, info in pairs(skyExplore) do
        if info["activity_id"] == id then
            pos = info["pos"];
            skyExplore[index] = nil;

            ME.user.dbase:set("sky_explore", skyExplore);
            break;
        end
    end

    EventMgr.fire(event.ACTIVITY_CLOSE, { ["id"] = id, ["pos"] = pos });
end

-- 获取所有正在进行中活动
function getCurrentActivities()
    local ret = {};

    for id, activity in pairs(currentActivities) do
        -- 判断是不是还没结束
        if tonumber(activity["close_time"]) >= TimeM.getServerTime() then
            ret[id] = activity;
        end
    end

    return ret;
end

-- 获取活动信息
function getActivityInfo(id)
    return currentActivities[id] or {};
end

-- 获取活动当前的状态
function getActivityStatus(activity_info)
    if not activity_info["pre_time"] or
        not activity_info["start_time"] or
        not activity_info["end_time"] or
        not activity_info["close_time"] then
        return ACTIVITY_STATUS_CLOSE;
    end

    if type(activity_info["status"]) == "string" then
        return activity_info["status"];
    end

    local serverTime = TimeM.getServerTime();
    if serverTime < activity_info["pre_time"] then
        -- 活动等待
        return ACTIVITY_STATUS_WAIT;
    elseif serverTime < activity_info["start_time"] then
        -- 活动准备
        return ACTIVITY_STATUS_PREPARE;
    elseif serverTime < activity_info["end_time"] then
        -- 活动开始
        return ACTIVITY_STATUS_START;
    elseif serverTime < activity_info["close_time"]then
        -- 活动结束
        return ACTIVITY_STATUS_END;
    end

    -- 活动关闭
    return ACTIVITY_STATUS_CLOSE;
end

-- 获取活动的兑换列表
function getActivityExchangeList(activityId)
    if not exchangeTableByActivity[activityId] then
        return {};
    end

    local ret = {};
    for id, info in pairs(exchangeTableByActivity[activityId]) do
        repeat
            -- 后置条件
            if tonumber(info["after_id"]) > 0 then
                -- 有后置项目的，已经兑换完就不再出现
                if getRemainExchangeAmount(activityId, info["id"]) <= 0 then
                    break;
                end
            end

            if tonumber(info["pre_id"]) > 0 then
                -- 有前置项目的，前置项目还没有兑换完不出现
                if getRemainExchangeAmount(activityId, info["pre_id"]) > 0 then
                    break;
                end
            end

            -- 复制下，避免修改到源数据
            local data = table.copy(info);

            -- 剩余可兑换数量
            local count = getRemainExchangeAmount(activityId, info["id"]);
            if type(info["desc"]) == "string" and string.len(info["desc"]) > 0 then
                data["desc"] = info["desc"];
            end

            if type(info["extra_desc"]) == "string" and string.len(info["extra_desc"]) > 0 then
                data["extra_desc"] = info["extra_desc"];
            end

            local dbase = info["dbase"];
            if type(dbase) == "table" then
                if type(dbase["goods_type"]) == "number" then
                    data["goods_type"] = dbase["goods_type"];
                end
                if type(dbase["icon"]) == "string" then
                    data["icon"] = dbase["icon"];
                end
            end

            data["count"] = count;
            table.insert(ret, data);
        until true
    end
    return ret;
end

-- 获取活动商品已兑换数量
function getExchangedAmount(activityId, id)
    local activityData = ME.user.dbase:query("activity") or {};
    if not activityData[activityId] or
       not activityData[activityId]["exchange"] then
        return 0;
    end

    return activityData[activityId]["exchange"][id] or 0;
end

-- 历史兑换次数
function getHistoryExchangedAmount(activityId, id)
    local activityData = ME.user.dbase:query("activity") or {};
    if not activityData[activityId] or
       not activityData[activityId]["history_exchange"] then
        return 0;
    end

    return activityData[activityId]["history_exchange"][id] or 0;
end

-- 获取剩余可兑换的数量
function getRemainExchangeAmount(activityId, id)
    local info = queryExchange(id);
    if not info or info["activity"] ~= activityId then
        return 0;
    end

    local dbase = info["dbase"] or {};
    local bonus = info["bonus"];
    if dbase["goods_type"] == 3 and type(bonus) == "table" and PetM.getMyPet(bonus[2]) then
        -- 英雄已经有了
        return 0;
    end

    if type(info["limit"]) ~= "number" and type(info["history_limit"]) ~= "number" then
        -- 不限次数
        return -1;
    elseif type(info["limit"]) == "number" and type(info["history_limit"]) == "number" then
        -- 两个都限制了，取当前可兑换和历史可兑换最小值
        return math.min(info["limit"] - getExchangedAmount(activityId, id),
            info["history_limit"] - getHistoryExchangedAmount(activityId, id));
    elseif type(info["history_limit"]) == "number" then
        -- 限制了历史
        return info["history_limit"] - getHistoryExchangedAmount(activityId, id);
    else
        -- 单次活动限制
        return info["limit"] - getExchangedAmount(activityId, id);
    end
end

-- 判断能否兑换
function canExchange(activityId, id, amount)
    if ActivityDungeonM.getCurrentActivityId() ~= activityId then
        trace("ActivityM", "无法兑换：活动(%d)不在进行中。", activityId);
        return false;
    end

    if not activityExchangeTable[id] then
        trace("ActivityM", "无法兑换：不存在id为%d的兑换配置。", id);
        return false;
    end

    local limit = activityExchangeTable[id]["limit"];
    local historyLimit = activityExchangeTable[id]["history_limit"];
    if type(limit) == "number" then
        local exchangedAmount = getExchangedAmount(activityId, id);
        if exchangedAmount + amount > limit then
            trace("ActivityM", "id为%d的商品可兑换数量不足%d个。", id, amount);
            return false;
        end
    end

    if type(historyLimit) == "number" then
        local exchangedAmount = getHistoryExchangedAmount(activityId, id);
        if exchangedAmount + amount > historyLimit then
            trace("ActivityM", "id为%d的商品可兑换数量不足%d个。", id, amount);
            return false;
        end
    end

    local price = activityExchangeTable[id]["price"];
    local curAmount, needAmount;
    if price[1] == 1 then
        local classId = price[2];
        curAmount = ItemM.getAmount(ME.user, classId);
        needAmount = amount * price[3];
        if curAmount < needAmount then
            trace("ActivityM", "物品(%d)数量不足，需求：%d， 当前：%d", classId, needAmount, curAmount);
            return string.format("item_%d_lack", classId);
        end
    elseif price[1] == 2 then
        local attrib = price[2];
        curAmount = ME.user:queryAttrib(attrib);
        needAmount = amount * price[3];
        if curAmount < needAmount then
            trace("ActivityM", "属性(%d)数量不足，需求：%d， 当前：%d", classId, needAmount, curAmount);
            return attrib .. "_lack";
        end
    else
        assert(false, "暂不支持的价格配置");
    end

    return true;
end

-- 更新曾开放活动
function updateOpenList(list)
    activityOpenList = list;
end

-- 活动曾开放活动
function getActivityOpenList()
    return activityOpenList;
end

-- 某个活动曾经是否开放过/当前没有开放
function hasActivityOpenOnce(id)
    local info = getActivityInfo(id);
    if getActivityStatus(info) == ACTIVITY_STATUS_START then
        -- 这个活动当前正在进行中，认为是false
        return false;
    end

    return activityOpenList[id] == 1;
end
-- 统计活动期间进入迷宫夹层的次数
function statEnterUreal(activityId, unrealId)
    local activityData = ME.user.dbase:query("activity") or {};
    activityData[activityId] = activityData[activityId] or {};
    activityData[activityId]["unreal_dungeon_stat"] = activityData[activityId]["unreal_dungeon_stat"] or {};

    local times = activityData[activityId]["unreal_dungeon_stat"][unrealId] or 0;
    times = times + 1;
    activityData[activityId]["unreal_dungeon_stat"][unrealId] = times;
    ME.user.dbase:set("activity", activityData);

    trace("ActivityM", "活动(%d)夹层迷宫(%d)的进入次数更新为：%d", activityId, unrealId, times);
end

-- 获取活动期间进入夹层迷宫的次数
function getEnterUnrealTimes(activityId, unrealId)
    local activityData = ME.user.dbase:query("activity") or {};
    if not activityData[activityId] or
       not activityData[activityId]["unreal_dungeon_stat"] then
        return 0;
    end

    return activityData[activityId]["unreal_dungeon_stat"][unrealId] or 0;
end

-- 根据活动物品查找活动ID
function getActivityIdByItem(classId)
    for _, id in pairs(table.keys(activityTable)) do
        local activityItems = query(id, "activity_items") or {};
        if table.indexOf(activityItems, classId) >= 0 then
            return id;
        end
    end

    return 0;
end